package com.iteaj.iot.server;

import com.iteaj.iot.*;
import com.iteaj.iot.codec.adapter.SocketMessageDecoderDelegation;
import com.iteaj.iot.codec.filter.CombinedInterceptor;
import com.iteaj.iot.config.ConnectProperties;
import com.iteaj.iot.server.codec.DeviceProtocolEncoder;
import com.iteaj.iot.server.handle.EventManagerHandler;
import com.iteaj.iot.server.handle.ProtocolBusinessHandler;
import com.iteaj.iot.server.manager.TcpDeviceManager;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

import static com.iteaj.iot.CoreConst.*;

/**
 * 设备的服务端组件基于TCP协议
 * 一种类型的设备(需要独立端口的)对应一套服务端组件
 */
public abstract class TcpServerComponent<M extends ServerMessage> extends SocketServerComponent<M, ByteBuf> {

    public TcpServerComponent(ConnectProperties connectProperties) {
        super(connectProperties);
    }

    public TcpServerComponent(ConnectProperties connectProperties, CombinedInterceptor filter) {
        super(connectProperties, filter);
    }

    @Override
    public TcpDeviceManager getDeviceManager() {
        return (TcpDeviceManager) super.getDeviceManager();
    }

    /**
     * 初始化父Channel
     * @return
     */
    @Override
    protected ServerBootstrap initParentChannel() {
        IotThreadManager threadManager = IotThreadManager.instance();
        return configOptions(new ServerBootstrap()
                .group(threadManager.getBossGroup(), threadManager.getWorkerGroup())
                .handler(new LoggingHandler(threadManager.getProperties().getLevel()))
                .channel(NioServerSocketChannel.class))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline p = ch.pipeline();
                    p.channel().attr(COMPONENT).set(TcpServerComponent.this);
                    TcpServerComponent.this.doInitChildChannel(p);
                }
            });
    }

    /**
     * 配置服务端和客户端连接的tcp参数
     * @param bootstrap
     * @return
     */
    protected ServerBootstrap configOptions(ServerBootstrap bootstrap) {
        return bootstrap;
    }

    protected void doInitChildChannel(ChannelPipeline p) {
        TcpServerComponent serverComponent = this;

        // 设置编码器
        p.addFirst(SERVER_ENCODER_HANDLER, DeviceProtocolEncoder.getInstance());

        // 设置解码器
        final ChannelInboundHandlerAdapter decoder = serverComponent.getMessageDecoder();
        if(decoder == null) {
            throw new ProtocolException("未指定设备报文解码器：" + serverComponent.getName());
        }

        if(decoder instanceof SocketMessageDecoderDelegation) {
            if(((SocketMessageDecoderDelegation<?>) decoder).getDelegation() == null) {
                ((SocketMessageDecoderDelegation<?>) decoder).setDelegation(serverComponent);
            }
        }

        p.addFirst(SERVER_DECODER_HANDLER, decoder);

        // 有一个值设定, 就启用
        final ConnectProperties config = serverComponent.config();
        if(config.getReaderIdleTime() > 0 || config.getAllIdleTime() > 0
                || config.getWriterIdleTime() > 0) {
            p.addLast(IDLE_STATE_EVENT_HANDLER, new IdleStateHandler(config.getReaderIdleTime()
                    , config.getWriterIdleTime(), config.getAllIdleTime(), TimeUnit.SECONDS));
        }

        // 新增事件管理处理
        final EventManagerHandler instance = EventManagerHandler.getInstance();
        if(p.get(IDLE_STATE_EVENT_HANDLER) != null) { // 如果有启用超时处理
            p.addAfter(IDLE_STATE_EVENT_HANDLER, EVENT_MANAGER_HANDLER, instance);
        } else {
            p.addLast(EVENT_MANAGER_HANDLER, instance);
        }

        // 最后设置业务处理器
        p.addLast(SERVER_SERVICE_HANDLER, ProtocolBusinessHandler.getInstance());

        // 自定义处理器
        serverComponent.doInitChannel(p);
    }

    @Override
    protected ChannelManager createDeviceManager() {
        return (ChannelManager) FrameworkManager.createDeviceManager(this);
    }

    @Override
    public PortType getPortType() {
        return PortType.Tcp;
    }

    @Override
    public synchronized void close() {
        if(isStart()) {
            // 关闭所有客户端channel
            TcpDeviceManager deviceManager = getDeviceManager();
            if(deviceManager != null && deviceManager.size() > 0) {
                deviceManager.close().awaitUninterruptibly();
            }

            // 关闭服务端channel
            super.close();
        }
    }
}
